package com.dingwen.treasure.kettle.utils;

import cn.hutool.core.collection.CollUtil;
import com.dingwen.treasure.kettle.base.tree.BaseTree;
import com.dingwen.treasure.kettle.exception.TreeBuilderException;
import org.springframework.util.Assert;

import java.lang.reflect.Constructor;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 　TreeUtil: 构建递归的通用工具类： 本工具类不做排序实现，请保证传入的ts已遵循业务规则排序
 *
 * <p>枚举说明：</p>
 *  <ul>
 *      <li>T ： 需要进行递归的对象类型</li>
 *      <li>R ：递归后返回的对象类型</li>
 *  </ul>
 * 　@author dingwen
 * 　@date 2022/6/22
 */
public class TreeUtil {


    /**
     * 构建和转换
     *
     * @param ts          ts
     * @param topParentId 顶级父id
     * @param rClass      r类
     * @param tClass      t类
     * @return {@link List}<{@link R}>
     */
    public static <R extends BaseTree, T extends BaseTree> List<R> builderAndConvert(List<T> ts, String topParentId, Class<R> rClass, Class<T> tClass) {
        List<T> result = builder(ts, topParentId);
        return convert(result, rClass, tClass);
    }

    /**
     * 构建
     *
     * @param ts          ts
     * @param topParentId 顶级父id
     * @return {@link List}<{@link R}>
     */
    public static <R, T extends BaseTree> List<T> builder(List<T> ts, String topParentId) {
        Assert.notNull(topParentId, "必须指定顶级父id");
        // 存储返回的结果
        List<T> result = CollUtil.newArrayList();

        // 顶层节点
        ts.forEach(ele -> {
            if (ele.getParenId().equals(topParentId)) {
                recursion(ts, ele);
                result.add(ele);
            }
        });
        return CollUtil.isEmpty(result) ? ts : result;
    }

    /**
     * 递归转换： 调用返回对象的有参数构造器进行转换 参数类型为T
     *
     * @param ts     ts
     * @param rClass r
     * @param tClass t
     * @return {@link List}<{@link R}>
     */
    private static <R extends BaseTree, T extends BaseTree> List<R> convert(List<T> ts, Class<R> rClass, Class<T> tClass) {
        return ts.stream().map(ele -> {
            try {
                Constructor<R> constructor = rClass.getDeclaredConstructor(tClass);
                R r = constructor.newInstance(ele);
                List children = ele.getChildren();
                if (CollUtil.isNotEmpty(children)) {
                    List convertChildren = convert(children, rClass, tClass);
                    r.setChildren(convertChildren);
                }
                return r;
            } catch (Exception e) {
                throw new TreeBuilderException("通用树构建异常，请确保提供了正确的构造方法");
            }
        }).collect(Collectors.toList());
    }


    /**
     * 递归
     *
     * @param ts ts
     * @param t  t
     */
    private static <R extends BaseTree, T extends BaseTree> void recursion(List<T> ts, T t) {
        List<T> children = getChildren(ts, t);
        t.setChildren(children);
        children.forEach(ele -> {
                    if (hasChildren(ts, ele)) {
                        recursion(ts, ele);
                    }
                });
    }


    /**
     * 获取子项
     *
     * @param ts ts
     * @param t  t
     * @return {@link List}<{@link T}>
     */
    private static <R, T extends BaseTree> List<T> getChildren(List<T> ts, T t) {
        return ts.stream()
                .filter(ele -> ele.getParenId().equals(t.getId()))
                .collect(Collectors.toList());
    }

    /**
     * 判断是否还有孩子
     *
     * @param ts ts
     * @param t  t型
     * @return boolean
     */
    private static <R, T extends BaseTree> boolean hasChildren(List<T> ts, T t) {
        return CollUtil.isNotEmpty(getChildren(ts, t));
    }

}
